"""
Market Data Service V2 - Refactored Architecture
=================================================

轻量级的市场数据服务，完全基于适配器架构重构。

核心职责：
1. 作为"总指挥"，协调各个适配器的工作
2. 实现业务逻辑层，提供高级API
3. 管理数据流向（查询 → 缓存 → 存储）
4. 提供统一的异常处理和监控

特点：
- 依赖注入：所有依赖通过构造函数注入
- 零耦合：不直接依赖任何具体的数据源或数据库
- 配置驱动：数据源选择完全由配置决定
- 可测试：易于Mock和单元测试

作者: 架构组
创建日期: 2025-10-05
版本: v2.0
"""

import logging
import functools
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from decimal import Decimal

from ...adapters.manager import AdapterManager
from ...adapters.core.base import HistoricalDataAdapter, RealtimeDataAdapter
from ...adapters.core.models import Bar, Tick, Orderbook
from ...adapters.core.exceptions import (
    AdapterError,
    AdapterConnectionError,
    AdapterDataError,
    AdapterTimeoutError,
)
from .influxdb_writer_service import InfluxDBWriterService
from .cache_service import CacheService

# 导入监控工具
from backend.redfire_framework.monitoring import (
    get_metrics_manager, timer, increment, set_gauge, observe_histogram
)

logger = logging.getLogger(__name__)


# ==================== 监控装饰器 ====================

def monitor_method(method_name: str = None):
    """监控服务方法性能和调用情况"""
    def decorator(func):
        name = method_name or f"{func.__module__}.{func.__name__}"
        
        @functools.wraps(func)
        async def wrapper(self, *args, **kwargs):
            import time
            increment(f"market_data_service.{name}.calls")
            
            start_time = time.time()
            try:
                result = await func(self, *args, **kwargs)
                
                # 记录执行时间
                duration = time.time() - start_time
                observe_histogram(f"market_data_service.{name}.duration", duration)
                
                increment(f"market_data_service.{name}.success")
                return result
                
            except Exception as e:
                increment(f"market_data_service.{name}.errors")
                logger.error(f"Method {name} failed: {e}", exc_info=True)
                raise
        
        return wrapper
    return decorator


def track_data_source(source: str):
    """跟踪数据源操作"""
    def decorator(func):
        @functools.wraps(func)
        async def wrapper(self, *args, **kwargs):
            import time
            increment(f"data_source.{source}.requests")
            
            start_time = time.time()
            try:
                result = await func(self, *args, **kwargs)
                
                # 记录执行时间
                duration = time.time() - start_time
                observe_histogram(f"data_source.{source}.duration", duration)
                
                increment(f"data_source.{source}.success")
                return result
                
            except Exception as e:
                increment(f"data_source.{source}.errors")
                raise
        
        return wrapper
    return decorator


# ==================== 核心服务类 ====================

class MarketDataServiceV2:
    """
    市场数据服务 V2 - 重构版
    
    这是一个轻量级的"总指挥"，它的职责是：
    1. 协调各个适配器（通过AdapterManager）
    2. 实现高级业务逻辑
    3. 管理缓存和数据持久化
    4. 提供统一的API接口
    
    不做的事情（委托给其他组件）：
    - 直接访问数据源 → AdapterManager + 具体Adapter
    - 数据写入逻辑 → InfluxDBWriterService
    - 缓存逻辑 → CacheService
    - WebSocket推送 → WebSocketService（独立服务）
    
    示例用法：
        >>> # 在main.py中初始化
        >>> adapter_manager = AdapterManager(config=service_config)
        >>> await adapter_manager.initialize()
        >>> 
        >>> writer_service = InfluxDBWriterService(adapter_manager)
        >>> cache_service = CacheService(...)
        >>> 
        >>> service = MarketDataServiceV2(
        ...     adapter_manager=adapter_manager,
        ...     writer_service=writer_service,
        ...     cache_service=cache_service
        ... )
        >>> 
        >>> # 查询历史K线
        >>> bars = await service.get_historical_bars(
        ...     symbol='000001.SZ',
        ...     start_time=datetime(2025, 1, 1),
        ...     end_time=datetime(2025, 10, 4),
        ...     frequency='1d',
        ...     source='tushare'  # 或者 'influxdb'
        ... )
    """
    
    def __init__(
        self,
        adapter_manager: AdapterManager,
        writer_service: Optional[InfluxDBWriterService] = None,
        cache_service: Optional[CacheService] = None,
    ):
        """
        初始化市场数据服务V2
        
        Args:
            adapter_manager: 适配器管理器（必需）
            writer_service: 写入服务（可选，如果不需要写入功能可以为None）
            cache_service: 缓存服务（可选，如果不需要缓存可以为None）
        """
        self.adapter_manager = adapter_manager
        self.writer_service = writer_service
        self.cache_service = cache_service
        
        logger.info("MarketDataServiceV2 initialized")
    
    # ==================== 历史数据查询 ====================
    
    @monitor_method("get_historical_bars")
    async def get_historical_bars(
        self,
        symbol: str,
        start_time: datetime,
        end_time: datetime,
        frequency: str = "1d",
        source: str = "influxdb",
        use_cache: bool = True,
        **kwargs
    ) -> List[Bar]:
        """
        查询历史K线数据
        
        这是核心方法，支持从不同数据源查询历史K线：
        - 'influxdb': 从InfluxDB数据库查询（最快，推荐）
        - 'tushare': 从Tushare API查询（用于数据补全）
        - 'ctp': 从CTP查询历史数据（如果适配器支持）
        
        数据流程：
        1. 如果启用缓存，先查缓存
        2. 缓存未命中，从指定适配器查询
        3. 查询结果写入缓存
        4. 返回数据
        
        Args:
            symbol: 标的代码（如 '000001.SZ'）
            start_time: 开始时间
            end_time: 结束时间
            frequency: 数据频率（'1m', '5m', '1h', '1d' 等）
            source: 数据源名称（'influxdb', 'tushare', 'ctp'）
            use_cache: 是否使用缓存
            **kwargs: 传递给适配器的额外参数
        
        Returns:
            List[Bar]: K线数据列表
        
        Raises:
            AdapterError: 适配器相关错误
            ValueError: 参数错误
        """
        logger.info(
            f"Querying bars: symbol={symbol}, start={start_time}, end={end_time}, "
            f"freq={frequency}, source={source}"
        )
        
        # 1. 参数验证
        if not symbol:
            raise ValueError("Symbol cannot be empty")
        if start_time >= end_time:
            raise ValueError("Start time must be before end time")
        
        # 2. 尝试从缓存获取
        if use_cache and self.cache_service:
            cache_key = f"bars:{source}:{symbol}:{frequency}:{start_time.isoformat()}:{end_time.isoformat()}"
            cached_data = await self.cache_service.get(cache_key)
            
            if cached_data:
                logger.info(f"Cache hit for {cache_key}")
                increment("market_data_service.cache.hit")
                return cached_data
            else:
                increment("market_data_service.cache.miss")
        
        # 3. 从适配器查询
        adapter = self.adapter_manager.get_adapter(source)
        if not adapter:
            raise AdapterError(f"Adapter '{source}' not found or not initialized")
        
        if not isinstance(adapter, HistoricalDataAdapter):
            raise AdapterError(f"Adapter '{source}' does not support historical data queries")
        
        # 4. 执行查询
        try:
            bars = await adapter.query_bars(
                symbol=symbol,
                start_time=start_time,
                end_time=end_time,
                frequency=frequency,
                **kwargs
            )
            
            logger.info(f"Retrieved {len(bars)} bars from {source}")
            
            # 5. 写入缓存
            if use_cache and self.cache_service and bars:
                await self.cache_service.set(cache_key, bars, ttl=300)  # 5分钟缓存
            
            return bars
            
        except Exception as e:
            logger.error(f"Failed to query bars from {source}: {e}", exc_info=True)
            raise
    
    @monitor_method("get_historical_ticks")
    async def get_historical_ticks(
        self,
        symbol: str,
        start_time: datetime,
        end_time: datetime,
        source: str = "influxdb",
        **kwargs
    ) -> List[Tick]:
        """
        查询历史Tick数据
        
        Args:
            symbol: 标的代码
            start_time: 开始时间
            end_time: 结束时间
            source: 数据源名称
            **kwargs: 额外参数
        
        Returns:
            List[Tick]: Tick数据列表
        """
        logger.info(f"Querying ticks: symbol={symbol}, source={source}")
        
        adapter = self.adapter_manager.get_adapter(source)
        if not adapter:
            raise AdapterError(f"Adapter '{source}' not found")
        
        if not isinstance(adapter, HistoricalDataAdapter):
            raise AdapterError(f"Adapter '{source}' does not support historical data")
        
        try:
            ticks = await adapter.query_ticks(
                symbol=symbol,
                start_time=start_time,
                end_time=end_time,
                **kwargs
            )
            
            logger.info(f"Retrieved {len(ticks)} ticks from {source}")
            return ticks
            
        except NotImplementedError:
            logger.warning(f"Adapter '{source}' does not support tick queries")
            return []
        except Exception as e:
            logger.error(f"Failed to query ticks: {e}", exc_info=True)
            raise
    
    # ==================== 实时数据查询 ====================
    
    @monitor_method("get_realtime_ticks")
    async def get_realtime_ticks(
        self,
        symbol: str,
        source: str = "tushare",
        use_cache: bool = True,
        **kwargs
    ) -> List[Tick]:
        """
        获取实时Tick数据（快照模式）
        
        与订阅模式不同，这是直接查询当前时刻的实时行情快照。
        适用于需要即时获取当前价格的场景。
        
        支持的数据源：
        - 'tushare': 使用 Tushare的realtime_quote接口（推荐，纯爬虫，不需要积分）
        - 'akshare': 使用 AKShare 的实时行情接口
        - 'ctp': 使用 CTP 实时数据（期货）
        
        Args:
            symbol: 标的代码（支持单个或逗号分隔的多个代码）
            source: 数据源名称
            use_cache: 是否使用缓存（默认True，缓存时间较短）
            **kwargs: 传递给适配器的额外参数
        
        Returns:
            List[Tick]: Tick数据列表
        
        Raises:
            AdapterError: 适配器相关错误
            ValueError: 参数错误
        
        示例:
            >>> # 获取单个股票实时行情
            >>> ticks = await service.get_realtime_ticks(symbol="000001.SH", source="tushare")
            >>> 
            >>> # 获取多个股票实时行情
            >>> ticks = await service.get_realtime_ticks(
            ...     symbol="000001.SH,399001.SZ,000300.SH",
            ...     source="tushare"
            ... )
        """
        logger.info(f"查询实时Tick: symbol={symbol}, source={source}")
        
        # 1. 参数验证
        if not symbol:
            raise ValueError("Symbol cannot be empty")
        
        # 处理多个symbol的情况
        symbols = [s.strip() for s in symbol.split(',')]
        
        # 2. 尝试从缓存获取（缓存时间很短，如5秒）
        if use_cache and self.cache_service:
            cache_key = f"realtime_ticks:{source}:{symbol}"
            cached_data = await self.cache_service.get(cache_key)
            
            if cached_data:
                logger.info(f"Cache hit for {cache_key}")
                increment("market_data_service.realtime_cache.hit")
                return cached_data
            else:
                increment("market_data_service.realtime_cache.miss")
        
        # 3. 从适配器查询
        adapter = self.adapter_manager.get_adapter(source)
        if not adapter:
            raise AdapterError(f"Adapter '{source}' not found or not initialized")
        
        # 4. 调用适配器获取实时数据
        try:
            # 优先尝试调用 get_realtime_quote 方法（Tushare适配器特有）
            if hasattr(adapter, 'get_realtime_quote'):
                ticks = await adapter.get_realtime_quote(symbols=symbols, **kwargs)
            elif isinstance(adapter, RealtimeDataAdapter):
                # 对于其他实时适配器，可能需要不同的方法
                # 这里暂时抛出提示
                raise AdapterError(
                    f"Adapter '{source}' is a realtime adapter but doesn't support get_realtime_quote. "
                    f"Please use subscribe_realtime_ticks instead."
                )
            else:
                raise AdapterError(f"Adapter '{source}' does not support realtime data queries")
            
            logger.info(f"Retrieved {len(ticks)} realtime ticks from {source}")
            
            # 5. 写入缓存（缓存时间很短，如5秒）
            if use_cache and self.cache_service and ticks:
                await self.cache_service.set(cache_key, ticks, ttl=5)  # 5秒缓存
            
            return ticks
            
        except Exception as e:
            logger.error(f"Failed to query realtime ticks from {source}: {e}", exc_info=True)
            raise
    
    # ==================== 实时数据订阅 ====================
    
    @monitor_method("subscribe_realtime_ticks")
    async def subscribe_realtime_ticks(
        self,
        symbols: List[str],
        source: str = "ctp",
        auto_save: bool = True,
    ) -> None:
        """
        订阅实时Tick数据
        
        这个方法会：
        1. 从AdapterManager获取支持实时数据的适配器
        2. 注册一个回调函数
        3. 回调函数会自动将Tick数据写入InfluxDB（如果auto_save=True）
        
        Args:
            symbols: 要订阅的标的列表
            source: 实时数据源名称（如 'ctp'）
            auto_save: 是否自动保存到InfluxDB
        
        Raises:
            AdapterError: 适配器相关错误
        """
        logger.info(f"Subscribing to ticks: symbols={symbols}, source={source}")
        
        adapter = self.adapter_manager.get_adapter(source)
        if not adapter:
            raise AdapterError(f"Adapter '{source}' not found")
        
        if not isinstance(adapter, RealtimeDataAdapter):
            raise AdapterError(f"Adapter '{source}' does not support realtime data")
        
        # 定义回调函数
        async def on_tick_received(tick: Tick):
            """接收到Tick数据时的回调"""
            try:
                logger.debug(f"Received tick: {tick.symbol} @ {tick.price}")
                increment(f"realtime_ticks.{source}.received")
                
                # 自动保存到InfluxDB
                if auto_save and self.writer_service:
                    await self.writer_service.write_tick(tick)
                
            except Exception as e:
                logger.error(f"Error processing tick: {e}", exc_info=True)
                increment(f"realtime_ticks.{source}.errors")
        
        # 订阅
        try:
            await adapter.subscribe_tick(symbols=symbols, callback=on_tick_received)
            logger.info(f"Successfully subscribed to {len(symbols)} symbols on {source}")
            
        except Exception as e:
            logger.error(f"Failed to subscribe: {e}", exc_info=True)
            raise
    
    @monitor_method("unsubscribe_realtime_ticks")
    async def unsubscribe_realtime_ticks(
        self,
        symbols: List[str],
        source: str = "ctp"
    ) -> None:
        """
        取消订阅实时Tick数据
        
        Args:
            symbols: 要取消订阅的标的列表
            source: 数据源名称
        """
        logger.info(f"Unsubscribing from ticks: symbols={symbols}, source={source}")
        
        adapter = self.adapter_manager.get_adapter(source)
        if not adapter or not isinstance(adapter, RealtimeDataAdapter):
            logger.warning(f"Realtime adapter '{source}' not found")
            return
        
        try:
            await adapter.unsubscribe_tick(symbols=symbols)
            logger.info(f"Successfully unsubscribed from {len(symbols)} symbols")
            
        except Exception as e:
            logger.error(f"Failed to unsubscribe: {e}", exc_info=True)
    
    # ==================== 业务逻辑方法 ====================
    
    @monitor_method("get_latest_price")
    async def get_latest_price(
        self,
        symbol: str,
        source: str = "influxdb"
    ) -> Optional[Decimal]:
        """
        获取最新价格
        
        这是一个业务逻辑方法，实现：
        1. 查询最近1天的K线数据
        2. 返回最后一根K线的收盘价
        
        Args:
            symbol: 标的代码
            source: 数据源
        
        Returns:
            Optional[Decimal]: 最新价格，如果没有数据返回None
        """
        logger.info(f"Getting latest price for {symbol} from {source}")
        
        try:
            # 查询最近1天的日线数据
            end_time = datetime.now()
            start_time = end_time - timedelta(days=1)
            
            bars = await self.get_historical_bars(
                symbol=symbol,
                start_time=start_time,
                end_time=end_time,
                frequency="1d",
                source=source
            )
            
            if bars:
                latest_bar = bars[-1]  # 最后一根K线
                return latest_bar.close
            else:
                logger.warning(f"No data found for {symbol}")
                return None
                
        except Exception as e:
            logger.error(f"Failed to get latest price: {e}", exc_info=True)
            return None
    
    @monitor_method("get_shanghai_index_today")
    async def get_shanghai_index_today(self) -> Optional[Dict[str, Any]]:
        """
        获取今日上证指数数据
        
        这是一个具体的业务逻辑示例，展示如何基于新架构实现业务需求。
        
        Returns:
            Optional[Dict]: 上证指数数据，包含开高低收等信息
        """
        logger.info("Getting Shanghai Index data for today")
        
        symbol = "000001.SH"  # 上证指数
        today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        tomorrow = today + timedelta(days=1)
        
        try:
            # 1. 先尝试从InfluxDB查询（最快）
            bars = await self.get_historical_bars(
                symbol=symbol,
                start_time=today,
                end_time=tomorrow,
                frequency="1d",
                source="influxdb",
                use_cache=True
            )
            
            # 2. 如果InfluxDB没有数据，从Tushare获取
            if not bars:
                logger.info("No data in InfluxDB, fetching from Tushare")
                bars = await self.get_historical_bars(
                    symbol=symbol,
                    start_time=today,
                    end_time=tomorrow,
                    frequency="1d",
                    source="tushare",
                    use_cache=False
                )
                
                # 3. 将Tushare的数据写入InfluxDB（数据补全）
                if bars and self.writer_service:
                    logger.info("Saving Tushare data to InfluxDB")
                    for bar in bars:
                        await self.writer_service.write_bar(bar)
            
            # 4. 返回结果
            if bars:
                bar = bars[0]
                return {
                    "symbol": bar.symbol,
                    "timestamp": bar.timestamp.isoformat(),
                    "open": float(bar.open),
                    "high": float(bar.high),
                    "low": float(bar.low),
                    "close": float(bar.close),
                    "volume": float(bar.volume),
                    "amount": float(bar.amount) if bar.amount else None,
                }
            else:
                logger.warning(f"No data found for {symbol} today")
                return None
                
        except Exception as e:
            logger.error(f"Failed to get Shanghai Index data: {e}", exc_info=True)
            return None
    
    # ==================== 数据采集方法 ====================
    
    @monitor_method("fetch_and_store_bars")
    @track_data_source("fetch_and_store")
    async def fetch_and_store_bars(
        self,
        symbol: str,
        start_time: datetime,
        end_time: datetime,
        frequency: str = "1d",
        source: str = "tushare"
    ) -> int:
        """
        从外部数据源获取数据并存储到InfluxDB
        
        这是一个数据采集方法，用于：
        1. 从外部API（如Tushare）获取历史数据
        2. 将数据批量写入InfluxDB
        3. 返回写入的数据条数
        
        Args:
            symbol: 标的代码
            start_time: 开始时间
            end_time: 结束时间
            frequency: 数据频率
            source: 数据源名称（通常是外部API如'tushare'）
        
        Returns:
            int: 写入的数据条数
        """
        logger.info(
            f"Fetching and storing bars: symbol={symbol}, "
            f"start={start_time}, end={end_time}, source={source}"
        )
        
        if not self.writer_service:
            raise RuntimeError("Writer service not configured")
        
        try:
            # 1. 从数据源获取数据
            bars = await self.get_historical_bars(
                symbol=symbol,
                start_time=start_time,
                end_time=end_time,
                frequency=frequency,
                source=source,
                use_cache=False  # 不使用缓存，确保数据是最新的
            )
            
            if not bars:
                logger.warning(f"No bars fetched for {symbol}")
                return 0
            
            # 2. 批量写入InfluxDB
            for bar in bars:
                await self.writer_service.write_bar(bar)
            
            # 3. 刷新缓冲区，确保数据立即写入
            await self.writer_service.flush()
            
            logger.info(f"Successfully stored {len(bars)} bars for {symbol}")
            return len(bars)
            
        except Exception as e:
            logger.error(f"Failed to fetch and store bars: {e}", exc_info=True)
            raise
    
    # ==================== 健康检查 ====================
    
    async def health_check(self) -> Dict[str, Any]:
        """
        健康检查
        
        检查所有依赖组件的健康状态：
        - AdapterManager及其管理的所有适配器
        - WriterService
        - CacheService
        
        Returns:
            Dict: 健康状态报告
        """
        health_status = {
            "service": "market_data_service_v2",
            "status": "healthy",
            "components": {},
            "timestamp": datetime.now().isoformat()
        }
        
        try:
            # 1. 检查适配器
            adapter_health = await self.adapter_manager.health_check()
            health_status["components"]["adapters"] = adapter_health
            
            # 2. 检查写入服务
            if self.writer_service:
                writer_health = await self.writer_service.health_check()
                health_status["components"]["writer"] = writer_health
            
            # 3. 检查缓存服务
            if self.cache_service:
                cache_health = await self.cache_service.health_check()
                health_status["components"]["cache"] = cache_health
            
            # 4. 判断整体状态
            all_healthy = all(
                status for status in adapter_health.values()
            )
            
            if not all_healthy:
                health_status["status"] = "degraded"
            
        except Exception as e:
            logger.error(f"Health check failed: {e}", exc_info=True)
            health_status["status"] = "unhealthy"
            health_status["error"] = str(e)
        
        return health_status
    
    # ==================== 信息查询 ====================
    
    def get_available_adapters(self) -> List[str]:
        """
        获取所有可用的适配器名称
        
        Returns:
            List[str]: 适配器名称列表
        """
        return self.adapter_manager.list_adapters()
    
    def get_adapter_info(self) -> Dict[str, Dict[str, Any]]:
        """
        获取所有适配器的详细信息
        
        Returns:
            Dict: 适配器信息
        """
        return self.adapter_manager.get_adapter_info()

